package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/quic-go/quic-go"
)

// handleUploadNotification 处理上传通知
func (c *QUICTunnelClient) handleUploadNotification(stream *quic.Stream, msg *TunnelMessage) {
	startTime := time.Now()
	defer func() {
		duration := time.Since(startTime)
		log.Printf("🏁 [上传拉取] 处理完成: 耗时=%.2fs", duration.Seconds())
	}()

	// 解析通知消息
	notification, err := parseUploadNotification(msg.Body)
	if err != nil {
		log.Printf("❌ [上传拉取] 解析通知失败: %v", err)
		errorMsg := NewErrorMessage(c.tunnelID, msg.RequestID, 1, fmt.Sprintf("解析通知失败: %v", err))
		errorMsg.Write(stream)
		(*stream).Close()
		return
	}

	requestID := notification.RequestID
	log.Printf("📋 [上传拉取] 通知内容: RequestID=%s, TunnelID=%s",
		requestID[:8]+"...", notification.TunnelID[:8]+"...")

	// 1️⃣ 获取元数据，判断是否为大文件
	log.Printf("🔍 [上传拉取] 获取元数据: RequestID=%s", requestID[:8]+"...")
	meta, err := c.getUploadMetadata(requestID)
	if err != nil {
		log.Printf("❌ [上传拉取] 获取元数据失败: %v", err)
		errorMsg := NewErrorMessage(c.tunnelID, requestID, 2, fmt.Sprintf("获取元数据失败: %v", err))
		errorMsg.Write(stream)
		(*stream).Close()
		return
	}

	log.Printf("📊 [上传拉取] 元数据: Size=%.2f MB, 大文件=%v, 分片数=%d",
		float64(meta.ContentLength)/(1024*1024), meta.IsLargeFile, meta.TotalChunks)

	// 2️⃣ 根据文件大小选择拉取策略
	var uploadData *UploadData
	pullStart := time.Now()

	if meta.IsLargeFile && meta.TotalChunks > 0 {
		// 大文件：并发分片拉取
		log.Printf("📦 [上传拉取] 大文件模式: 并发拉取 %d 个分片", meta.TotalChunks)
		uploadData, err = c.pullLargeFileInChunks(requestID, meta)
	} else {
		// 小文件：一次性拉取
		log.Printf("📦 [上传拉取] 小文件模式: 一次性拉取", )
		uploadData, err = c.pullUploadFromServer(requestID)
	}

	if err != nil {
		log.Printf("❌ [上传拉取] 拉取失败: %v", err)
		errorMsg := NewErrorMessage(c.tunnelID, requestID, 3, fmt.Sprintf("拉取失败: %v", err))
		errorMsg.Write(stream)
		(*stream).Close()
		return
	}

	pullDuration := time.Since(pullStart)
	log.Printf("✅ [上传拉取] 拉取成功: Size=%.2f MB, 耗时=%.2fs, 速度=%.2f MB/s",
		float64(len(uploadData.Body))/(1024*1024),
		pullDuration.Seconds(),
		float64(len(uploadData.Body))/(1024*1024)/pullDuration.Seconds())

	// 3️⃣ 上传到本地服务
	log.Printf("🚀 [上传拉取] 开始上传到本地: %s %s", uploadData.Method, uploadData.Path)
	uploadStart := time.Now()

	response, err := c.uploadToLocalService(uploadData)
	if err != nil {
		log.Printf("❌ [上传拉取] 本地上传失败: %v", err)
		errorMsg := NewErrorMessage(c.tunnelID, requestID, 3, fmt.Sprintf("本地上传失败: %v", err))
		errorMsg.Write(stream)
		(*stream).Close()
		return
	}
	defer response.Body.Close()

	uploadDuration := time.Since(uploadStart)
	log.Printf("✅ [上传拉取] 本地上传成功: Status=%d, 耗时=%.2fs",
		response.StatusCode, uploadDuration.Seconds())

	// 4️⃣ 读取响应并返回给服务端
	responseBody, err := io.ReadAll(response.Body)
	if err != nil {
		log.Printf("❌ [上传拉取] 读取响应失败: %v", err)
		errorMsg := NewErrorMessage(c.tunnelID, requestID, 5, fmt.Sprintf("读取响应失败: %v", err))
		errorMsg.Write(stream)
		(*stream).Close()
		return
	}

	// 构造HTTP响应
	var httpResponse bytes.Buffer
	httpResponse.WriteString(fmt.Sprintf("HTTP/1.1 %d %s\r\n", response.StatusCode, response.Status))

	// 写入响应头
	for key, values := range response.Header {
		for _, value := range values {
			httpResponse.WriteString(fmt.Sprintf("%s: %s\r\n", key, value))
		}
	}

	httpResponse.WriteString("\r\n")
	httpResponse.Write(responseBody)

	// 🔥🔥🔥 关键架构变更：通过HTTP/2返回响应（与原有逻辑一致）
	// 而不是通过QUIC Stream直接返回
	log.Printf("🚀 [上传拉取] 通过HTTP/2发送响应: RequestID=%s, Size=%d bytes",
		requestID[:8]+"...", httpResponse.Len())

	http2SendStart := time.Now()
	err = c.sendResponseViaHTTP2(requestID, httpResponse.Bytes())
	http2SendDuration := time.Since(http2SendStart)

	if err != nil {
			log.Printf("❌ [上传拉取] HTTP/2发送响应失败: %v, 耗时=%.2fs", err, http2SendDuration.Seconds())
		errorMsg := NewErrorMessage(c.tunnelID, requestID, 6, fmt.Sprintf("HTTP/2发送失败: %v", err))
		errorMsg.Write(stream)
		(*stream).Close()
		return
	}

	log.Printf("✅ [上传拉取] HTTP/2响应已发送: 耗时=%.2fs", http2SendDuration.Seconds())

	// 5️⃣ 清理服务端缓存
	go c.deleteUploadCache(requestID)

	// 关闭QUIC Stream
	(*stream).Close()
}

// getUploadMetadata 获取上传元数据
func (c *QUICTunnelClient) getUploadMetadata(requestID string) (*UploadMetadata, error) {
	url := fmt.Sprintf("%s/api/upload/cache/%s/meta", c.serverURL, requestID)

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	// 🚀 使用共享的HTTP客户端
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("服务端返回错误: %d", resp.StatusCode)
	}

	var meta UploadMetadata
	if err := json.NewDecoder(resp.Body).Decode(&meta); err != nil {
		return nil, fmt.Errorf("解析元数据失败: %v", err)
	}

	return &meta, nil
}

// pullLargeFileInChunks 并发拉取大文件分片
func (c *QUICTunnelClient) pullLargeFileInChunks(requestID string, meta *UploadMetadata) (*UploadData, error) {
	startTime := time.Now()
	log.Printf("📦 [分片拉取] 开始: 分片数=%d, 总大小=%.2f MB",
		meta.TotalChunks, float64(meta.ContentLength)/(1024*1024))

	// 创建结果切片
	chunks := make([][]byte, meta.TotalChunks)

	// 创建错误通道
	errChan := make(chan error, meta.TotalChunks)

	// 🔥 使用全局信号量（限制所有文件的总并发数）
	// 不再为每个文件创建独立的信号量，避免多文件上传时并发过高
	log.Printf("🚀 [分片拉取] 使用全局信号量（总并发=10）")
	
	// 进度跟踪
	var completedChunks int32
	var totalBytes int64
	var activeDownloads int32

	// 使用WaitGroup等待所有goroutine完成
	var wg sync.WaitGroup

	// 🚀 启动进度监控goroutine（每秒更新一次）
	progressDone := make(chan struct{})
	go func() {
		ticker := time.NewTicker(1 * time.Second)
		defer ticker.Stop()
		
		for {
			select {
			case <-ticker.C:
				elapsed := time.Since(startTime).Seconds()
				currentMB := float64(atomic.LoadInt64(&totalBytes)) / (1024 * 1024)
				speed := currentMB / elapsed
				progress := float64(atomic.LoadInt32(&completedChunks)) / float64(meta.TotalChunks) * 100
				active := atomic.LoadInt32(&activeDownloads)
				
				log.Printf("📊 [实时进度] %d/%d (%.1f%%), 已下载: %.2f MB, 速度: %.2f MB/s, 活跃下载: %d",
					atomic.LoadInt32(&completedChunks), meta.TotalChunks, progress, currentMB, speed, active)
			case <-progressDone:
				return
			}
		}
	}()

	// 🔥 并发拉取分片：先启动所有goroutine，让它们并发竞争信号量
	log.Printf("🚀 [并发启动] 启动 %d 个goroutine...", meta.TotalChunks)
	for i := 0; i < meta.TotalChunks; i++ {
		wg.Add(1)
		// 🔥 立即启动goroutine，不要在循环中等待
		go func(chunkIndex int) {
			defer wg.Done()

			// 🔥 使用全局信号量（限制所有文件的总并发数）
			if err := c.globalSem.Acquire(c.ctx, 1); err != nil {
				errChan <- fmt.Errorf("获取全局信号量失败: %v", err)
				return
			}
			defer c.globalSem.Release(1)

			// 标记活跃下载
			atomic.AddInt32(&activeDownloads, 1)
			log.Printf("🚀 [开始下载] Chunk=%d/%d", chunkIndex, meta.TotalChunks)
			
			// 拉取分片（带重试）
			chunkStart := time.Now()
			chunk, err := c.pullChunkWithRetry(requestID, chunkIndex, 3)
			chunkDuration := time.Since(chunkStart).Seconds()
			
			atomic.AddInt32(&activeDownloads, -1)
			
			if err != nil {
				log.Printf("❌ [下载失败] Chunk=%d, 耗时=%.2fs, Error=%v", chunkIndex, chunkDuration, err)
				errChan <- fmt.Errorf("拉取分片 %d 失败: %v", chunkIndex, err)
				return
			}

			chunks[chunkIndex] = chunk
			
			// 更新进度
			atomic.AddInt32(&completedChunks, 1)
			atomic.AddInt64(&totalBytes, int64(len(chunk)))
			
			log.Printf("✅ [下载完成] Chunk=%d/%d, Size=%.2f MB, 耗时=%.2fs",
				chunkIndex, meta.TotalChunks, float64(len(chunk))/(1024*1024), chunkDuration)
		}(i)
	}
	log.Printf("✅ [并发启动] 所有goroutine已启动，等待完成...")

	// 等待所有goroutine完成
	wg.Wait()
	close(progressDone)
	close(errChan)

	// 检查是否有错误
	for err := range errChan {
		if err != nil {
			return nil, err
		}
	}

	// 组装完整Body
	var fullBody bytes.Buffer
	for i, chunk := range chunks {
		if chunk == nil {
			return nil, fmt.Errorf("分片 %d 为空", i)
		}
		fullBody.Write(chunk)
	}

	log.Printf("✅ [分片拉取] 组装完成: %.2f MB", float64(fullBody.Len())/(1024*1024))

	return &UploadData{
		Method:        meta.Method,
		Path:          meta.Path,
		Headers:       meta.Headers,
		Body:          fullBody.Bytes(),
		ContentType:   meta.ContentType,
		IsChunked:     meta.IsChunked,
		ContentLength: meta.ContentLength,
	}, nil
}

// pullChunkWithRetry 带重试的分片拉取
func (c *QUICTunnelClient) pullChunkWithRetry(requestID string, chunkIndex int, maxRetries int) ([]byte, error) {
	var lastErr error

	for retry := 0; retry < maxRetries; retry++ {
		if retry > 0 {
			log.Printf("🔄 [分片拉取] 重试 %d/%d: Chunk=%d", retry, maxRetries, chunkIndex)
			time.Sleep(time.Duration(retry) * time.Second)
		}

		url := fmt.Sprintf("%s/api/upload/cache/%s/chunk/%d", c.serverURL, requestID, chunkIndex)

		req, err := http.NewRequest("GET", url, nil)
		if err != nil {
			lastErr = err
			continue
		}

		// 🚀 使用共享的HTTP客户端，支持真正的并发下载
		resp, err := c.httpClient.Do(req)
		if err != nil {
			lastErr = err
			continue
		}

		if resp.StatusCode != http.StatusOK {
			resp.Body.Close()
			lastErr = fmt.Errorf("服务端返回错误: %d", resp.StatusCode)
			continue
		}

		// 🚀 流式读取分片数据（避免阻塞）
		// 预分配缓冲区
		contentLength := resp.ContentLength
		var data []byte
		if contentLength > 0 {
			data = make([]byte, 0, contentLength)
		}
		
		// 使用缓冲读取器，每次读取64KB
		buf := make([]byte, 64*1024)
		for {
			n, err := resp.Body.Read(buf)
			if n > 0 {
				data = append(data, buf[:n]...)
			}
			if err == io.EOF {
				break
			}
			if err != nil {
				resp.Body.Close()
				lastErr = fmt.Errorf("读取数据失败: %v", err)
				break
			}
		}
		resp.Body.Close()

		if lastErr != nil {
			continue
		}

		// 成功拉取
		return data, nil
	}

	return nil, fmt.Errorf("拉取失败（重试%d次）: %v", maxRetries, lastErr)
}

// deleteUploadCache 删除服务端缓存
func (c *QUICTunnelClient) deleteUploadCache(requestID string) {
	url := fmt.Sprintf("%s/api/upload/cache/%s", c.serverURL, requestID)

	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		log.Printf("⚠️  [上传拉取] 创建删除请求失败: %v", err)
		return
	}

	// 🚀 使用共享的HTTP客户端
	resp, err := c.httpClient.Do(req)
	if err != nil {
		log.Printf("⚠️  [上传拉取] 删除缓存失败: %v", err)
		return
	}
	defer resp.Body.Close()

	log.Printf("🗑️  [上传拉取] 服务端缓存已清理: RequestID=%s", requestID[:8]+"...")
}

// UploadData 上传数据
type UploadData struct {
	Method        string
	Path          string
	Headers       map[string]string
	Body          []byte
	ContentType   string
	IsChunked     bool  // 是否为chunked编码
	ContentLength int64 // 原始Content-Length
}

// UploadMetadata 上传元数据
type UploadMetadata struct {
	RequestID     string            `json:"request_id"`
	TunnelID      string            `json:"tunnel_id"`
	Method        string            `json:"method"`
	Path          string            `json:"path"`
	Headers       map[string]string `json:"headers"`
	ContentType   string            `json:"content_type"`
	ContentLength int64             `json:"content_length"`
	IsChunked     bool              `json:"is_chunked"`
	IsLargeFile   bool              `json:"is_large_file"`
	ChunkSize     int64             `json:"chunk_size"`
	TotalChunks   int               `json:"total_chunks"`
}

// parseUploadNotification 解析上传通知
func parseUploadNotification(body []byte) (*UploadNotification, error) {
	content := string(body)

	// 简单解析: UPLOAD_NOTIFY\r\nRequestID: xxx\r\nTunnelID: yyy\r\n\r\n
	lines := strings.Split(content, "\r\n")

	notification := &UploadNotification{}

	for _, line := range lines {
		if strings.HasPrefix(line, "RequestID:") {
			notification.RequestID = strings.TrimSpace(line[10:])
		} else if strings.HasPrefix(line, "TunnelID:") {
			notification.TunnelID = strings.TrimSpace(line[9:])
		}
	}

	if notification.RequestID == "" {
		return nil, fmt.Errorf("RequestID为空")
	}

	return notification, nil
}

// UploadNotification 上传通知
type UploadNotification struct {
	RequestID string
	TunnelID  string
}

// pullUploadFromServer 从服务端拉取上传
func (c *QUICTunnelClient) pullUploadFromServer(requestID string) (*UploadData, error) {
	// 构造拉取URL
	url := fmt.Sprintf("%s/api/upload/cache/%s", c.serverURL, requestID)

	log.Printf("📥 [上传拉取] 请求URL: %s", url)

	// 创建 HTTP 请求
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %v", err)
	}

	// 🚀 使用共享的HTTP客户端（支持连接复用和更长的超时时间）
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求失败: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("服务端返回错误: %d", resp.StatusCode)
	}

	// 读取Body
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取Body失败: %v", err)
	}

	// 解析响应头获取元数据
	method := resp.Header.Get("X-Request-Method")
	path := resp.Header.Get("X-Request-Path")
	contentType := resp.Header.Get("Content-Type")
	isChunkedStr := resp.Header.Get("X-Is-Chunked")
	contentLengthStr := resp.Header.Get("X-Original-Content-Length")

	if method == "" {
		method = "POST"
	}
	if path == "" {
		path = "/"
	}

	// 🆕 解析chunked标记
	isChunked := (isChunkedStr == "true")
	var contentLength int64
	if contentLengthStr != "" {
		fmt.Sscanf(contentLengthStr, "%d", &contentLength)
	}

	// 解析原始请求头
	headers := make(map[string]string)
	for key, values := range resp.Header {
		if strings.HasPrefix(key, "X-Original-") {
			originalKey := strings.TrimPrefix(key, "X-Original-")
			if len(values) > 0 {
				headers[originalKey] = values[0]
			}
		}
	}

	// 🆕 显示chunked信息
	chunkedTag := ""
	if isChunked {
		chunkedTag = " [CHUNKED]"
	}

	log.Printf("📦 [上传拉取] 元数据: Method=%s, Path=%s, ContentType=%s%s, Headers=%d",
		method, path, contentType, chunkedTag, len(headers))

	return &UploadData{
		Method:        method,
		Path:          path,
		Headers:       headers,
		Body:          body,
		ContentType:   contentType,
		IsChunked:     isChunked,
		ContentLength: contentLength,
	}, nil
}

// uploadToLocalService 上传到本地服务
func (c *QUICTunnelClient) uploadToLocalService(data *UploadData) (*http.Response, error) {
	// 构造本地URL（使用配置的本地地址）
	localURL := fmt.Sprintf("http://localhost:%d%s", c.localPort, data.Path)

	log.Printf("🎯 [上传拉取] 本地URL: %s", localURL)

	// 创建HTTP请求
	req, err := http.NewRequest(data.Method, localURL, bytes.NewReader(data.Body))
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %v", err)
	}

	// 🆕 根据原始请求设置Content-Length或Transfer-Encoding
	if data.IsChunked {
		// 原始请求是chunked，移除Content-Length，让客户端自动处理
		req.Header.Set("Transfer-Encoding", "chunked")
		log.Printf("📦 [上传拉取] 使用chunked编码上传 (原始长度=%d)", data.ContentLength)
	} else {
		// 明确设置Content-Length
		req.ContentLength = int64(len(data.Body))
		log.Printf("📦 [上传拉取] 使用Content-Length上传: %d bytes", len(data.Body))
	}

	// 设置Content-Type
	req.Header.Set("Content-Type", data.ContentType)

	// 复制其他头部
	for key, value := range data.Headers {
		// 跳过一些不需要的头
		lowerKey := strings.ToLower(key)
		if lowerKey == "host" || lowerKey == "connection" ||
			lowerKey == "content-length" || lowerKey == "transfer-encoding" {
			continue // 这些头已经处理过了
		}
		req.Header.Set(key, value)
	}

	// 设置Host为localhost
	req.Host = fmt.Sprintf("localhost:%d", c.localPort)

	// 发送请求
	client := &http.Client{
		Timeout: 120 * time.Second, // 本地服务可能需要时间处理
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求失败: %v", err)
	}

	return resp, nil
}

// sendResponseViaHTTP2 通过HTTP/2混合隧道发送响应到服务端
func (c *QUICTunnelClient) sendResponseViaHTTP2(requestID string, responseBody []byte) error {
	// 🔥🔥🔥 关键修复：使用HTTP/2连接池发送响应（而不是创建新的HTTP客户端）
	// 这样才能复用HTTP/2混合隧道的连接和特性
	if c.http2Pool == nil {
		return fmt.Errorf("HTTP/2连接池未初始化")
	}

	log.Printf("📤 [HTTP/2响应] 准备通过连接池发送: RequestID=%s, Size=%d bytes",
		requestID[:8]+"...", len(responseBody))

	// 🚀 从连接池选择一个最优连接
	wrapper := c.http2Pool.SelectConnection()
	if wrapper == nil {
		return fmt.Errorf("HTTP/2连接池无可用连接")
	}

	// 🚀 使用选中连接的SendResponseZeroCopy方法发送响应
	// 这个方法会自动处理多路复用、流控、错误处理等
	err := wrapper.SendResponseZeroCopy(requestID, bytes.NewReader(responseBody))
	if err != nil {
		log.Printf("❌ [HTTP/2响应] 发送失败: %v", err)
		return fmt.Errorf("HTTP/2发送失败: %v", err)
	}

	log.Printf("✅ [HTTP/2响应] 发送成功: RequestID=%s", requestID[:8]+"...")
	return nil
}
